/*
 Ajanta - Java Linear Programming Library

 Copyright 2010 Raghu Kaippully.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
package logic.simplex.model;

/**
 * A constraint used in an {@link LPProblem}.
 *
 * <p/>
 * A constraint is of the standard form:
 *
 * <pre>
 * a<sub>1</sub>x<sub>1</sub> + a<sub>2</sub>x<sub>2</sub> + ... + a<sub>n</sub>x<sub>n</sub> (&le;, =, &ge;) b
 * </pre>
 *
 * where
 * <code>a<sub>i</sub></code> are coefficients and b is a constant.
 */
public class LPConstraint {

    /**
     * The operator used by a constraint
     */
    public static enum Operator {

        LessOrEqual, GreaterOrEqual
    }
    /**
     * The LHS of this constraint represented as a function
     */
    private LPFunction lhs = new LPFunction();
    /**
     * The operator used by this constraint
     */
    private Operator operator;
    /**
     * The RHS constant of this constraint.
     */
    private double rhsConstant;

    /**
     * Constructs a new LP constraint. The constraint is effectively "blank".
     */
    public LPConstraint() {
    }

    /**
     * Convenient constructor by specifying one term of the LHS of a constraint.
     *
     * @param coefficient the coefficient of the LHS term
     * @param variable the LP variable of the LHS term
     */
    public LPConstraint(double coefficient, LPVariable variable) {
        plus(coefficient, variable);
    }

    /**
     * Add a new term to the LHS of this constraint.
     *
     * @param coefficient the coefficient of the LHS term
     * @param variable the LP variable of the LHS term
     * @return this LP constraint
     */
    public LPConstraint plus(double coefficient, LPVariable variable) {
        lhs.plus(coefficient, variable);
        return this;
    }

    /**
     * Adds a new term with a negative coefficient to the LHS of this
     * constraint.
     *
     * @param coefficient the coefficient of the LHS term
     * @param variable the LP variable of the LHS term
     * @return this LP constraint
     */
    public LPConstraint minus(double coefficient, LPVariable variable) {
        lhs.minus(coefficient, variable);
        return this;
    }

    /**
     * Sets the RHS constant of this constraint.
     *
     * @param constant the RHS constant value
     * @return this LP constraint
     * @throws IllegalArgumentException if constant is negative
     */
    public LPConstraint lessOrEqualTo(double constant) {
        if (constant < 0) {
            throw new IllegalArgumentException();
        }
        operator = Operator.LessOrEqual;
        rhsConstant = constant;
        return this;
    }

    /**
     * Sets the RHS constant of this constraint with a >= operation. This will
     * be converted to a <= operation by implicitly adding a surplus variable.
     *

     *
     * @param constant the RHS constant value
     * @return this LP constraint
     * @throws IllegalArgumentException if constant is negative
     */
    public LPConstraint greaterOrEqualTo(double constant) {
        if (constant < 0) {
            throw new IllegalArgumentException();
        }
        operator = Operator.GreaterOrEqual;
        rhsConstant = constant;
        return this;
    }

    /**
     * Returns the LHS expression of this constraint.
     *
     * @return the linear expression on the LHS of this constraint
     */
    public LPFunction getLHSExpression() {
        return lhs;
    }

    /**
     * Returns the operator of this constraint.
     *
     * @return the operator of this constraint
     */
    public Operator getOperator() {
        return operator;
    }

    /**
     * Returns the constant on the RHS side of this constraint.
     *
     * @return the constant on the RHS side of this constraint
     */
    public double getRHSConstant() {
        return rhsConstant;
    }

    @Override
    public String toString() {
        return lhs + " <= " + rhsConstant;
    }
}
